import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.Locale;
import java.util.Random; 



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.Droite;
import pluginUtils.MobiusTransform;
import pluginUtils.CircleInversion;
import pluginUtils.PackCircle;
import pluginUtils.Point2D;
import pluginUtils.Pos3D;
import pluginUtils.Sphere;
import pluginUtils.SphereInversion;


public class GenericDrawerSpirals extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	private PrintStream output;
	private double xShift=0; 
	private double zShift=0; 
	private double limit,lmoins; 
	
	

	private Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	

	private void drawCircle(Point2D C,double r){
		double xCenter=C.getX(); 
		double yCenter=C.getY(); 
	 
		
		int intX=(int)((xCenter)*acoef+ccoef);
		int intY=Y-(int)((yCenter)*vcoef+wcoef);
		int intRx=(int)(r*acoef);
		int intRy=(int)(r*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
	}
	

	private void drawPoint(double x,double y){
		int intX=(int)(x*acoef+ccoef);
		int intY=Y-(int)(y*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	private void drawPoint(Point2D A){
		drawPoint(A.getX(),A.getY()); 
	}
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,Y-YD,XF,Y-YF); 
	}
	
	private void drawLine(Point2D A,Point2D B){
		drawLine(A.getX(),A.getY(),B.getX(),B.getY()); 
	}
	
	private void drawLine(Complexe A,Complexe B){
		drawLine(A.getReal(),A.getIm(),B.getReal(),B.getIm()); 
	}
		
	public static void affiche(int t[]){
		System.out.print("{");
		for(int i=0;i<t.length;i++){
			System.out.print(t[i]+" "); 
			if(i<t.length-1) System.out.print(","); 
		}
		System.out.println("},"); 
			
	}
	
	
	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
	
		
		 limit=100; 
		 lmoins=-100;
	
		setBounds(lmoins,limit,lmoins,limit); 
		setCoefs(); 
		
		
		
		
		
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		// T=kz
		Complexe aComplex=Complexe.createComplexeFromRI(-1,1);
		Complexe bComplex=Complexe.createComplexeFromRI(0.707,2); 
		Complexe c=Complexe.createComplexeFromRI(1,1);
		Complexe d=Complexe.createComplexeFromRI(-1,0.707); 
	
		MobiusTransform T=new MobiusTransform(aComplex,bComplex,c,d); 
		
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		primeIP.setLineWidth(3); 
		
		drawLine(lmoins,0,limit,0); 
		drawLine(0,lmoins,0,limit); 

		setProcessor("Verifying", primeIP);
		show();
		System.out.println("debut"); 	
	
		double incAngle=0.1; 	
		double phi=0;
		double init=-10; 
		double end=10; 
		double step=0.01; 
		while(phi<Math.PI){
		double current=init;
		Point2D courant=new Point2D(0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
		while(current<end){
			Point2D suivant=new Point2D(0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
			System.out.println(courant);
			primeIP.setColor(Color.BLACK);
			drawLine(T.image(courant),T.image(suivant));
			primeIP.setColor(Color.BLUE);
			drawLine(courant,suivant); 
			//primeIP.setColor(Color.RED);
			//drawLine(courant.getX(),courant.getY(),T.image(courant).getReal(),T.image(courant).getIm());
			courant=suivant; 
			current+=step; 
		}
		
		current=init;
		courant=new Point2D(0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), -Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
		while(current<end){
			Point2D suivant=new Point2D(0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), -Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
			System.out.println(courant);
			primeIP.setColor(Color.BLACK);
			drawLine(T.image(courant),T.image(suivant));
			primeIP.setColor(Color.BLUE);
			drawLine(courant,suivant); 
			//primeIP.setColor(Color.RED);
			//drawLine(courant.getX(),courant.getY(),T.image(courant).getReal(),T.image(courant).getIm());
			courant=suivant; 
			current+=step; 
		}
		
		 current=init;
	     courant=new Point2D(1+0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), -Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
			while(current<end){
				Point2D suivant=new Point2D(1+0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), -Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
				System.out.println(courant);
				primeIP.setColor(Color.BLACK);
				drawLine(T.image(courant),T.image(suivant));
				primeIP.setColor(Color.BLUE);
				drawLine(courant,suivant); 
				//primeIP.setColor(Color.RED);
				//drawLine(courant.getX(),courant.getY(),T.image(courant).getReal(),T.image(courant).getIm());
				courant=suivant; 
				current+=step; 
			}
			
			
			current=init;
		     courant=new Point2D(1+0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
				while(current<end){
					Point2D suivant=new Point2D(1+0.5*Math.sinh(current)/(Math.cosh(current)+Math.cos(phi)), Math.sin(phi)/(Math.cosh(current)+Math.cos(phi)));
					System.out.println(courant);
					primeIP.setColor(Color.BLACK);
					drawLine(T.image(courant),T.image(suivant));
					primeIP.setColor(Color.BLUE);
					drawLine(courant,suivant); 
					//primeIP.setColor(Color.RED);
					//drawLine(courant.getX(),courant.getY(),T.image(courant).getReal(),T.image(courant).getIm());
					courant=suivant; 
					current+=step; 
				}
			
		phi+=incAngle;
		updateAndDraw(); 
		}
		 
		 System.out.println("fin"); 

	}	
}
	